package com.itttq.gen.service;


import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.itttq.gen.common.conf.GenProperties;
import com.itttq.gen.common.constant.Constants;
import com.itttq.gen.common.constant.StatusTypeEnums;
import com.itttq.gen.generator.GenProject;
import com.itttq.gen.generator.TableInfo;
import com.itttq.gen.mapper.IProjectMapper;
import com.itttq.gen.model.po.AccountPo;
import com.itttq.gen.model.po.ProjectGenHisPo;
import com.itttq.gen.model.po.ProjectPo;
import com.itttq.gen.model.qo.ProjectQo;
import com.itttq.gen.model.to.ResultTo;
import com.itttq.gen.utils.GenUtil;
import com.itttq.gen.utils.ZipUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;

import java.io.IOException;
import java.util.List;

@Service
@Slf4j
public class ProjectService {
    @Autowired
    private IProjectMapper projectMapper;
    @Autowired
    private ProjectGenHisService projectGenHisService;
    @Autowired
    private GenProject genProject;
    @Autowired
    private GenProperties genProps;

    /**
     * 根据ID查询对象信息
     *
     * @param id
     */
    public ProjectPo getProject(long id) {
        return projectMapper.selectById(id);
    }

    /**
     * 根据ID删除对象
     *
     * @param id
     */
    public void delProject(long id) {
        int rs = projectMapper.deleteById(id);
        Assert.isTrue(rs > 0, ResultTo.getCodeAndMsg(ResultTo.ResultCode.FAIL, "删除数据失败"));
    }

    /**
     * 根据ID集合批量删除对象
     *
     * @param ids ID的List集合
     */
    public void delProjectByIds(List<Long> ids) {
        int rs = projectMapper.deleteBatchIds(ids);
        Assert.isTrue(rs > 0, ResultTo.getCodeAndMsg(ResultTo.ResultCode.FAIL, "批量删除数据失败"));
    }

    /**
     * 新增对象
     *
     * @param project 新增的PO对象
     */
    public void addProject(ProjectPo project) {
        int rs = projectMapper.insert(project);
        Assert.isTrue(rs > 0, ResultTo.getCodeAndMsg(ResultTo.ResultCode.FAIL, "新增数据失败"));
    }

    /**
     * 根据ID更新对象，对象的ID值必须传入
     *
     * @param project 更新的PO对象，必传ID值
     */
    public int updateProject(ProjectPo project) {
        return projectMapper.updateById(project);
    }

    /**
     * 根据条件查询记录数
     *
     * @param projectQo 查询对象
     * @return int 记录总数
     */
    public int getProjectCount(ProjectQo projectQo) {
        return projectMapper.selectCount(getQw(projectQo));
    }

    /**
     * 获取所有数据列表，不分页
     *
     * @param projectQo 查询对象
     * @return List<ProjectPo>
     */
    public List<ProjectPo> getProjects(ProjectQo projectQo) {
        return projectMapper.selectList(getQw(projectQo));
    }

    /**
     * 获取所有数据列表，并分页
     *
     * @param projectQo 查询对象
     * @return IPage<ProjectPo>
     */
    public IPage<ProjectPo> getProjectAndPage(ProjectQo projectQo) {
        return projectMapper.selectPage(new Page<>(projectQo.getPageNo(), projectQo.getPageSize()), getQw(projectQo));
    }

    /**
     * 构建Mybatis-Plus的查询条件对象。
     *
     * @param projectQo 查询对象
     * @return LambdaQueryWrapper<ProjectPo>
     */
    private LambdaQueryWrapper<ProjectPo> getQw(ProjectQo projectQo) {
        return new QueryWrapper<ProjectPo>().lambda()
                .eq(StringUtils.isNotEmpty(projectQo.getCode()), ProjectPo::getCode, projectQo.getCode())
                .eq(StringUtils.isNotEmpty(projectQo.getName()), ProjectPo::getName, projectQo.getName())
                .orderByDesc(ProjectPo::getUpdateTime);
    }

    /**
     * 根据项目ID生成项目
     *
     * @param projectId 项目ID
     */
    public ProjectPo genProject(long projectId, AccountPo account) {
        ProjectPo project = getProject(projectId);
        genProject(project, account);
        return project;
    }
    @Transactional(rollbackFor = Exception.class)
    public void genProject(ProjectPo project, AccountPo account) {
        Assert.notNull(project, ResultTo.getCodeAndMsg(ResultTo.ResultCode.DATA_NO, "项目不存在"));
        StatusTypeEnums.StatusEnums status = StatusTypeEnums.StatusEnums.ENABLE;
        String statusRemark = "成功";
        try {
            String dir = genProject.getProjectPath(project);
            String zipFileName = project.getCode() + ".zip";
            String zipFile = genProject.getParentPath(project)  + zipFileName;
            // 先操作数据库，因为后面的操作失败，数据库可以回滚
            project.setDownloadUrl(genProps.getProjectDownloadUrl(project.getCreator() + Constants.SLASH + zipFileName));
            updateProject(project);
            // 生成前先清空项目
            GenUtil.delFile(zipFile);
            genProject.genByProjectDir(project);
            // 压缩文件
            ZipUtils.toZip(dir, zipFile);
            // 压缩完成收删除目录
            GenUtil.delFile(dir);
        } catch (IOException e) {
            status = StatusTypeEnums.StatusEnums.DISABLE;
            statusRemark = "异常：" + e.getMessage();
            log.error("生成项目异常", e);
            Assert.isTrue(1 == 0, ResultTo.getCodeAndMsg(ResultTo.ResultCode.FAIL, "生成项目发生异常"));
        }
        try {
            // 插入项目生成历史，插入历史失败不影响正常的业务
            projectGenHisService.addProjectHis(ProjectGenHisPo.builder().projectId(project.getId()).projectName(project.getName())
                    .creator(account.getId()).creatorName(account.getName()).result(status)
                    .resultRemark(statusRemark).build());
        } catch (Exception e) {
            log.error("插入项目生成历史失败", e);
        }
    }
}
